package com.walleipt;

import javassist.*;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;

public class Javassist_Create_Class_Demo {

    public static void main(String[] args) throws CannotCompileException, NotFoundException, IllegalAccessException, InstantiationException, IOException
    {

        //CtClass对象容器
        ClassPool pool = ClassPool.getDefault();
        try {
            //创建Class
            CtClass pigerClass = pool.makeClass("com.walleipt.Piger");
            //阻止优化调整：优化调整减少内存使用，去除对象内的一些不必要的属性，优化调整后，方法签名和注解都是不可访问的
            pigerClass.stopPruning(true);

            //添加name属性
            CtField nameField = new CtField(pool.get("java.lang.String"), "name", pigerClass);
            nameField.setModifiers(Modifier.PRIVATE);
            pigerClass.addField(nameField);

            //生成get/set方法
            pigerClass.addMethod(CtNewMethod.getter("getName", nameField));
            pigerClass.addMethod(CtNewMethod.setter("setName", nameField));

            //生成构造函数
            CtConstructor c = new CtConstructor(new CtClass[] {}, pigerClass);
            c.setBody("{name=\"PT\";}");
            pigerClass.addConstructor(c);

            //添加say方法
            CtMethod ctm = new CtMethod(CtClass.voidType, "say", new CtClass[] {}, pigerClass);
            ctm.setModifiers(Modifier.PUBLIC);
            ctm.setBody("{ System.out.println(\"my name is \"+ name); }");
            pigerClass.addMethod(ctm);
            //调用生成的class类中的方法/这里可以用toClass()方法来加载类，也可以用java的类加载器来加载
            Class<?> clazz = pigerClass.toClass();
            Object o = clazz.newInstance();
            o.getClass().getMethod("say", new Class[] {})
                    .invoke(o, new Object[] {});
            //将class文件输出到系统文件中
            byte[] byteArr = pigerClass.toBytecode();
            FileOutputStream fos = new FileOutputStream(new File("D://Man.class"));
            fos.write(byteArr);
            fos.close();

        } catch (NotFoundException e) {
            e.printStackTrace();
        } catch (CannotCompileException e) {
            e.printStackTrace();
        }catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}
